#pragma once

#include "Socket.hpp"
#include <functional>
#include <pthread.h>
#include <sys/wait.h>

using namespace socket_ns;

const static in_port_t g_port = 8888;

using service_t = std::function<std::string(std::string&)>;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,
    ACCEPT_ERROR
};

class TcpServer
{
private:
    struct ThreadData
    {
        ThreadData(SockSPtr sockfd, TcpServer* self, const InetAddr& addr)
            : _socket(sockfd), _self(self), _addr(addr)
        {}

        SockSPtr _socket;
        TcpServer* _self;
        InetAddr _addr;
    };

private:
    static void* Execute(void* args)
    {
        // 将新线程分离 
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);

        std::string requeststr;
        int n = td->_socket->Recv(&requeststr);
        if (n > 0)
        {
            std::string responsestr = td->_self->_service(requeststr);
            td->_socket->Send(responsestr);
        }


        td->_socket->CloseSockfd();
        delete td;
        return nullptr;
    }

    void DeliveryThread(SockSPtr& iosocket, InetAddr& client)
    {
        pthread_t tid;
        ThreadData* td = new ThreadData(iosocket, this, client);
        pthread_create(&tid, nullptr, Execute, td);
    }

public:
    TcpServer(service_t service, in_port_t port = g_port)
        : _listensocket(std::make_shared<TcpSocket>()), 
          _port(port),
          _isrunning(false), 
          _service(service)
    {
        _listensocket->BuildListenSocket(port);
    }

    void Loop()
    {
        // signal(SIGCHLD, SIG_IGN);
        _isrunning = true;
        while (_isrunning)
        {
            // 获取新连接
            InetAddr client;
            SockSPtr iosocket = _listensocket->Accepter(&client);
            if (iosocket == nullptr)
                continue;
            LOG(INFO, "Get a new link, Client info: [%s], sockfd: %d\n", client.GetAddrStr().c_str(), iosocket->GetSockfd());

            // 给 Client 提供服务
            // Version - 3 ---> 多线程版本（原生接口手撕）
            DeliveryThread(iosocket, client);
        }
        _isrunning = false;
    }

    ~TcpServer()
    {
    }

private:
    SockSPtr _listensocket;  // 监听套接字，没有你怎么获取连接？
    in_port_t _port;         // 肯定需要端口号，不然怎么创建套接字？
    bool _isrunning;
    service_t _service;
};
